<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
<head>
<title>Curry kevytspesifikaatio</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="currytyyli.css" />
</head>

<body>
<!-- OTSIKKO: -->
<otsake>
Curry kevytspesifikaatio<br />
<tekijat>Kirjoittajat: Helle Majander ja Joonas Nietosvaara</tekijat>

</otsake>

<!-- SISÄLLYSLUETTELO: -->
<sisallys>
<a href="curryspesifikaatio.html">Sivun alkuun</a>
<br /> <br />
&nbsp<b><font color="#707070">Sisältö</font></b>
<ul>
<li><a href="#johdanto">Johdanto</a>
    <ul>
    <li><a href="#kielentaustaa">Kielen taustaa</a></li>

    <li><a href="#erityispiirteita">Erityispiirteitä</a></li>
    <li><a href="#etujajahaittoja1">Arvioita eduista ja haitoista</a></li>
    </ul></li>
<li><a href="#alkiorakenne">Alkiorakenne</a>
    <ul>
    <li><a href="#tunnukset">Tunnukset</a></li>
    <li><a href="#literaalivakiot">Literaalivakiot</a></li>

    <li><a href="#erottimet">Erottimet</a></li>
    <li><a href="#etujajahaittoja2">Arvioita eduista ja haitoista</a>
    </ul></li>
<li><a href="#nakyvyys">Tunnusten näkyvyysalueet</a>
    <ul>
    <li><a href="#lohkorakenne">Lohkorakenne</a></li>
    <li><a href="#sulkeumat">Sulkeumat</a></li>

    <li><a href="#arvojenkaytto">Arvojen käyttötavat</a></li>
    <li><a href="#sidontarekursiossa">Sidonta rekursiossa</a></li>
    <li><a href="#etujajahaittoja3">Arvioita eduista ja haitoista</a></li>
    </ul></li>
<li><a href="#ohjaus">Laskennan ohjaus</a>
    <ul>
    <li><a href="#funktiot">Funktiot</a></li>

    <li><a href="#operaattorit">Operaattorit</a></li>
    <li><a href="#valinta">Valinta</a></li>
    <li><a href="#toisto">Toisto</a></li>
    <li><a href="#rekursio">Rekursio</a></li>
    <li><a href="#etujajahaittoja4">Arvioita eduista ja haitoista</a></li>
    </ul></li>

<li><a href="#tietotyypit">Perustietotyypit</a>
    <ul>
    <li><a href="#alkeistyypit">Alkeistyypit</a></li>
    <li><a href="#perustyypit">Perustyypit</a></li>
    <li><a href="#kokoelmatyypit">Kokoelmatyypit</a></li>
    <li><a href="#tyypitys">Tyypitys</a></li>
    <li><a href="#etujajahaittoja5">Arvioita eduista ja haitoista</a></li>

    </ul></li>
<li><a href="#laskennankapselointi">Laskennan kapselointi</a>
    <ul>
    <li><a href="#aliohjelmat">Aliohjelmat</a></li>
    <li><a href="#parametrinvalitys">Parametrinvälitys</a></li>
    <li><a href="#virheisiinvarautuminen">Virheisiin varautuminen</a></li>
    <li><a href="#ohjelmanrakenne">Curry-ohjelman rakenne</a></li>

    <li><a href="#rinnakkaislaskenta">Rinnakkainen laskenta</a></li>
    <li><a href="#etujajahaittoja6">Arvioita eduista ja haitoista</a></li>
    </ul></li>
<li><a href="#datankapselointi">Datan kapselointi</a>
    <ul>
    <li><a href="#tietotyyppienmaar">Tietotyyppien määrittäminen</a></li>
    <li><a href="#olioohjelmoinnista">Olio-ohjelmoinnista</a></li>

    <li><a href="#etujajahaittoja7">Arvioita eduista ja haitoista</a></li>
    </ul></li>
<li><a href="#yhteenveto">Yhteenveto</a>
    <ul>
    <li><a href="#etujajahaittoja8">Arvioita eduista ja haitoista</a></li>
    <li><a href="#kayttokohteita">Käyttökohteita</a></li>
    </ul></li>

<li><a href="#lahteet">Lähteet</a></li>
</ul>
</sisallys>

<!-- SIVUN SISÄLTÖ: -->
<sisalto>
Luet Curry-ohjelmointikielen "kevytspesifikaatiota", joka on kirjoitettu
Helsingin Yliopiston Tietojenkäsittelytieteen laitoksen kevään 2011 kurssille
<a href="http://www.cs.helsinki.fi/u/wikla/OKP/K11/">Ohjelmointikielten periaatteet</a>.

<a name="johdanto" />
<hr />
<!-- ********* 1. harjoitusviikko: ******* -->

<h1>Johdanto</h1>

<p>Esittelemme tässä kappaleessa Curry-ohjelmointikielen yleisesti. Käymme läpi kielen taustaa, erilaisia toteutustapoja ja käyttökohteita. Esittelemme myös lyhyesti kielen erityispiirteitä.</p>
    
<a name="kielentaustaa" />
<h2>Kielen taustaa</h2>
<p>Curry on Haskell-pohjainen deklaratiivinen ohjelmointikieli, joka yhdistää funktionaalista ohjelmointia ja logiikkaohjelmointia. Kyseessä on alunperin mm. Michael Hanusinn luoma kokeilullinen kieli, jonka tarkoituksena on ollut yhteisen alustan luominen funktionaalisen logiikkaohjelmoinnin tutkimusta, opetusta ja sovellusten kehittämistä varten <a class="lahde" href="#lahteet">[AnH07]</a>.</p>

<p>Currya kehitettän ympäri maailmaa eri tutkimusryhmissä, minkä takia sille on myös useita erilaisia toteutustapoja. Tyypillisesti Curry-lähdekoodi käännetään jollekin toiselle ohjelmointikilelle, josta se käännetään suoritettavaksi ohjelmaksi kyseessä olevan kielen kääntäjällä. Tällaisia toteutuksia ovat esimerkiksi <a href="http://www.informatik.uni-kiel.de/~pakcs/">PAKCS</a> (Prolog), <a href="http://danae.uni-muenster.de/~lux/curry">MCC</a> (C) ja <a href="http://www.informatik.uni-kiel.de/prog/mitarbeiter/bernd-brassel/projects/">KiCS</a> (Haskell) <a class="lahde" href="#lahteet">[Han11a]</a>. Currylle on olemassa myös Javalla toteutettu virtuaalikone <a href="http://web.cecs.pdx.edu/~antoy/homepage/download.html">FLVM</a>. Tässä toteutuksessa Curry-ohjelmat käännetään välikielelle, jota FLVM-tulkki suorittaa <a class="lahde" href="#lahteet">[AHL05]</a>.</p>

<p>Curry on luonteensa takia suunnattu erityisesti funktionaalisia, loogisia ja rinnakkaisia paradigmoja koskevaan käyttöön <a class="lahde" href="#lahteet">[Han11a, Applications]</a>. Esimerkiksi hajautetuissa järjestelmissä toimivien ohjelmien <a class="lahde" href="#lahteet">[Han99]</a> ja graafisten käyttöliittymien toteuttaminen on suoraviivaista <a class="lahde" href="#lahteet">[Han00]</a>. Varsinaisten suoritettavien ohjelmien lisäksi Currya on käytetty muun muassa internetsivujen laatimiseen <a class="lahde" href="#lahteet">[AnH07; Han01]</a> ja tietokantasovelluksiin <a class="lahde" href="#lahteet">[Han04; Han11a, Applications]</a>.</p>

<a name="erityispiirteita" />

<h2>Erityispiirteitä</h2>

<p> Haskell-ohjelmointikielen ominaisuudet ovat lähes Curryn ominaisuuksien osajoukko. Siitä puuttuvat vain Haskellin tyyppiluokat (<i>typeclasses</i>). <a class="lahde" href="#lahteet">[Cur11]</a> Curry tarjoaa laiskan evaluointistrategian, joka pystyy käsittelemään äärettömiä rakenteita <a class="lahde" href="#lahteet">[AnH10]</a>. Yksi tärkeimmistä eroista muihin funktionaalisiin kieliin on ratkaisujen etsiminen, mikä tarkoittaa sellaisten arvojen etsimistä joukolle vapaita muuttujia että jokin tietty ehto toteutuu. Toinen Curryn tärkeä ominaisuus on mahdollisuus määritellä epädeterminististisiä funktioita, jotka voivat palauttaa samalla parametrilla useita eri arvoja. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Esimerkissä 1 esitetty Curry-ohjelma lukee yhden luvun ja tulostaa ensimmäisen Fibonaccin luvun joka on sitä suurempi. Ohjelma ajetaan helpoiten lataamalla se jonkun Curry-ympäristön interaktiiviseen tilaan ja antamalla komento <code>main</code>.</p>

<p>Funktio <code>fiblist</code>, joka alustetaan parametreilla 0 ja 1, laskee (äärettömän) Fibonaccin lukujen listan. Funktio <code>larger</code> etsii rekursiivisesti ensimmäisen listassa olevan alkion, joka on parametria <code>n</code> suurempi. Funktio <code>main</code> lukee syötteen, parsii sen kokonaisluvuksi funktiolla <code>readInt</code> ja tulostaa ensimmäisen Fibonaccin luvun, joka on syötettä suurempi. Laiskan evaluoinnin takia funktio <code>main</code> ei jää loputtomasti laskemaan uusia Fibonaccin lukuja. Se ei siis yritä evaluoida muodostamaamme ääretöntä listaa kokonaan, vaan lopettaa, kun halutun ehdon toteuttava luku on löytynyt.</p>

<box><b>Esimerkki 1. (Fibonaccin lukujen lista)</b><code>
<pre>import Read

fiblist x0 x1 = x0 : fiblist x1 (x0+x1)

larger n (fib:fibs) | fib > n   = fib
                    | otherwise = larger n fibs

main :: IO ()
main = do
  x <- getLine
  print (larger (readInt x) (fiblist 0 1))</pre>
</code></box>

<a name="etujajahaittoja1" />
<h2>Arvioita eduista ja haitoista</h2>
<p>Curry perii Haskellilta puhtaan funktionaalisuuden ja laiskuuden edut ja haitat. Kyseisiä etuja ja haittoja on tutkittu paljon, ja tässä osiossa aihetta käsitellään vain lyhyesti.</p>

<p>Puhtaan funktionaalisessa kielessä funktion tyyppi kertoo, suorittaako funktio syöttöä tai tulostusta. Myöskään muuttujia tai tilaa ei ole olemassa ellei niitä oteta käyttöön tyyppitasolla näkyvällä tavalla. Sivuvaikutuksia rajoittamalla nämä ominaisuudet tekevät ohjelman käyttäytymisen helpommin ymmärrettäväksi ja ennustettavaksi, mutta toisaalta niiden käyttö on usein aloittejalle hankalaa.</p>

<p>Laiskuus mahdollistaa äärettömien tietorakenteiden käsittelyn, mikä tekee koodista tiiviimpää, koska evaluointia ei tarvitse erikseen pysäyttää, kun kohtaa äärettömän rakenteen. Toisaalta tämä tekee annetun lausekkeen lopullisen evaluointihetken, ja siten muistin käytön, joskus ennalta-arvaamattomaksi.</p>

<hr />

<a name="alkiorakenne" />
<h1>Alkiorakenne</h1>

<p>Tässä kappaleessa perehdymme tarkemmin siihen, millaisista osista Curry-ohjelmat rakennetaan. Käsittelemme tunnusten nimeämistä, literaalivakioita sekä ohjelmakoodissa käytettäviä erottimia.</p>

<a name="tunnukset" />
<h2>Tunnukset</h2>
<p>Curry-ohelmissa tunnuksia käytetään funktioiden, muuttujien ja tietotyyppien nimeämiseen. Isoilla ja pienillä kirjaimilla on merkitystä, eli <code>abc</code> on eri asia kun <code>Abc</code> <a class="lahde" href="#lahteet">[Han06]</a>. Funktiot ja muuttujat nimetään yleensä aloittaen pienellä kirjaimella, jota voi seurata kirjaimia, numeroita ja alaviivoja <a class="lahde" href="#lahteet">[AnH07]</a>. Tietotyyppien nimet aloitetaan yleensä isolla kirjaimella. Kääntäjä kuitenkin hyväksyy kaikki nimeämiskäytännöt, mikäli sitä ei erikseen kehoteta varoittamaan poikkeavista nimistä <a class="lahde" href="#lahteet">[Han06]</a>. Erityistä tunnusta <code>_</code> käytetään merkitsemään nimetöntä muuttujaa (<i>anonymous variable</i>), joka ei vaikuta funktion arvoon <a class="lahde" href="#lahteet">[AnH07]</a>.</p>

<p>Alla listatut sanat ovat varattuja sanoja, joita ei voi käyttää tunnuksina <a class="lahde" href="#lahteet">[Han06]</a>:</p>
<box>
<code>case data do else external free if infix infixl infixr import in let module of then type where</code>
</box>

<a name="literaalivakiot" />
<h2>Literaalivakiot</h2>
<p>Curryn formaalissa spesifikaatiossa literaaleiksi on määritelty kokonaisluvut, merkit, merkkijonot ja liukuluvut. Literaalivakiot ovat kuten Javassa: <a class="lahde" href="#lahteet">[Han06]</a></p>

<box>
<table>
<tr><th>Literaali</th><th>Tunnus</th><th>Literaalivakioita</th></tr>
<tr><td>kokonaisluku</td><td><code>Int</code></td><td><code>..., -2, -1, 0, 1, 2, ...</code></td></tr>
<tr><td>merkki</td><td><code>Char</code></td><td><code>'a', 'b', 'c', ..., '\n', ...</code></td></tr>
<tr><td>merkkijono</td><td><code>String</code></td><td><code>"hello", "world"</code></td></tr>

<tr><td>liukuluku</td><td><code>Float</code></td><td><code>3.14159, 5.0e-4</code></td></tr>
</table>
</box>

<p>Literaalien lisäksi käytännössä kaikissa Curryn tärkeimmissä toteutuksissa on määritelty joukko perustietotyyppejä. Yleisimpien tietotyyppien käyttöä on helpotettu literaalivakioiden kaltaisella merkintätavalla: <a class="lahde" href="#lahteet">[Han06]</a></p>

<box>
<table>
<tr><th>Tyyppi</th><th>Tunnus</th><th>Esimerkkejä</th></tr>

<tr><td>totuusarvo</td><td><code>Bool</code></td><td><code>False, True</code></td></tr>
<tr><td>tyyppiä <code>T</code> oleva lista</td><td><code>[T]</code></td><td><code>[], [1,2,3], 1:2:3:[]</code></td></tr>
<tr><td>tyyppien <code>T_1, ..., T_n</code> tuppeli</td><td><code>(T_1, ..., T_n)</code></td><td><code>(1,2,3), (False, "viesti")</code></td></tr>

<tr><td>onnistuminen</td><td><code>Success</code></td><td><code>success</code></td></tr>
<tr><td>yksikkö (<i>Unit</i>)</td><td><code>()</code></td><td><code>()</code></td></tr>
</table>
</box>

<p>Erilaisia tietotyyppejä käsitellään tarkemmin luvussa <a href="#tietotyypit">Perustietotyypit</a>.</p>

<a name="erottimet" />
<h2>Erottimet</h2>
<p>Curry-ohjelmakoodissa erottimina käytetään välilyöntejä (<i>whitespace</i>) ja sulkuja <code>(</code> ja <code>)</code>. Funktioiden määrittelyssä parametrit erottetaan funktion nimestä välilyönneillä ja lohkot määritellään sisennysten avulla. Sulkuja käytetään suoritusjärjestyksen määräämiseen.</p>

<p>Avainsanat <code>let</code>, <code>where</code>, <code>do</code> ja <code>of</code> aloittavat lohkon. Lohkoja, jotka alkavat sanoilla <code>where</code> ja <code>let</code>, käytetään sisäkkäisten lohkorakenteiden määrittelyyn (luku <a href="#nakyvyys">Tunnusten näkyvyysalueet</a>), <code>do</code>-lohkoa käytetään I/O-operaatioiden yhteydessä (luku <a href="#laskennankapselointi">Laskennan kapselointi</a>) ja <code>of</code>-lohko liittyy <code>case</code>-valintalauseeseen (luku <a href="#ohjaus">Laskennan ohjaus</a>).</p>

<p>Lohko sisältää listan lausekkeita, joiden sisennys on saman suuruinen. Rivit, joilla on suurempi sisennys tulkitaan edellistä riviä jatkaviksi. Lohko päättyy riviin, jonka sisennys on pienempi kuin lohkon lausekkeilla. Ylimmän tason määrittelyt eivät saa alkaa välilyönneillä. <a class="lahde" href="#lahteet">[Han06]</a></p>

<p>Esimerkissä 2 funktion <code>fib n</code> määrittely sisältää avainsanalla <code>case</code> alkavan lohkon, joka koostuu kolmesta lausekkeesta. Vimeisessä lauskekkeessa määrätään suoritusjärjestys sulkujen avulla: <code>fib (k-1)</code> antaa parametria <code>k-1</code> vastaavan Fibonaccin luvun, kun <code>fib k-1</code> antaisi parametria <code>k</code> vastaavan Fibonaccin luvun, josta vähennetään luku <code>1</code>.</p>

<box><b>Esimerkki 2. (Fibonaccin lukuja funktiolla)</b><code><pre>
fib n = case n of
  0 -> 0
  1 -> 1
  k -> fib (k-1) + fib (k-2)</pre></code></box>

<p>Koska rivit, joilla on suurempi sisennys, tulkitaan edellistä riviä jatkaviksi, esimerkiksi funktiomäärittelyt voidaan kirjoittaa usealle riville, kunhan kaikki rivit ensimmäisen jälkeen on sisennetty vähintään yhden merkin verran. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Curry-ohjelmaan voi lisätä kommentteja kahdella tavalla: merkeillä <code>--</code> aloitetaan kommentti, joka päättyy rivin loppuun ja <code>{-</code> aloittaa kommentin, joka päättyy loppumerkkeihin <code>-}</code> <a class="lahde" href="#lahteet">[Han06]</a>.</p>

<a name="etujajahaittoja2" />
<h2>Arvioita eduista ja haitoista</h2>
<p>Curryn tunnusten nimeämiskäytäntö sekä literaalivakiot ja tavallisimmat tyypit vaikuttavat esimerkiksi Java-koodiin tottuneelle melko intuitiivisilta. Lohkojen merkitseminen sisennysten avulla helpottaa ohjelmakoodin kirjoittamista, mutta toisaalta voi johtaa melko epäselvään koodiin.</p>

<!-- ********* 2. harjoitusviikko: ******* -->
<hr />

<a name="nakyvyys" />
<h1>Tunnusten näkyvyysalueet</h1>

<p>Perehdymme tässä luvussa tarkemmin siihen, millä tavalla tunnukset Curry-ohjelmissa sidotaan. Lohkorakenteita käytettäessä on tiedettävä, mitkä ovat tunnusten näkyvyysalueet eli missä osissa ohjelmakoodia kukin tunnus on käytössä. Esittelemme myös, miten tunnusten sidonta käyttäytyy rekursiossa.</p>

<a name="lohkorakenne" />
<h2>Lohkorakenne</h2>

<p>Curryssa näkyvyysalueet ovat staattisia eli tunnusten näkyvyys määräytyy ohjelman kirjoitusasusta, ei sen suorituksesta. Yhteys, jossa tunnus esiintyy, määrää sen näkyvyysalueen. Esimerkiksi funktiomäärittelyn vasemmalla puolella esitellyt paikalliset muuttujat ovat näkyvissä vain funktion sisällä. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Tyypillisesti ohjelmoija ei pysty vaikuttamaan tunnusten näkyvyysalueisiin, mutta on olemassa muutamia poikkeuksia, joissa ohjelmoija pystyy rajoittamaan tunnuksen näkyvyyttä. Tällaisia paikallisia näkyvyysalueita (<i>local scope</i>) eli sulkeumia (<i>closure</i>) on mahdollista määrittää käyttämällä <code>where</code>- ja <code>let ... in</code>-lohkoja. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<a name="sulkeumat" />
<h2>Sulkeumat</h2>
<p>Sulkeuman määrittäviä <code>where</code>- ja <code>let ... in</code>-lohkoja käytetään funktioiden määrittelyssä <a class="lahde" href="#lahteet">[Han06]</a>. Esimerkissä 3 on esitetty funktio, joka kääntää sille parametrina annetun listan. Funktion sisällä <code>where</code>-lohkossa on määritelty vain paikallisesti näkyvä rekursiivinen funktio <code>aux</code>, joka kääntää listan siirtämällä sen alusta yhden alkion kerrallaan uuteen listaan.  Esimerkissä 4 taas on määritelty funktio joka laskee n. Fibonaccin luvun nopeasti. Paikallista näkyvyvyyttä on käytetään molemmissa funktiossa samaan tarkoitukseen: määrittelemään paikallinen, ulospäin näkymätön apufunktio. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 3. (Listan kääntäminen - where)</b><code><pre>
revList l = aux l []
  where aux [] r = r
        aux (u:v) r = aux v (u:r)
</pre></code></box>

<box><b>Esimerkki 4. (Nopea Fibonacci - let ... in)</b><code><pre>
fib n = let
  go a b k = if k <= 0 then a else go b (a+b) (k-1) in
  go 0 1 n
</pre></code></box>

<p>Lohkoja <code>where</code> ja <code>let ... in</code> voi olla useita sisäkkäin. Ulompien lohkojen tunnukset ovat sisempien käytössä, mutta ne voidaan peittää määrittelemällä sisemmässä lohkossa uusi samanniminen tunnus. <a class="lahde" href="#lahteet">[AnH07]</a> Lohko <code>where</code> on ilmaisuvoimaltaan <code>let ... in</code>-lohkoa suurempi koska <code>where</code>-lohko voi sitoa tunnuksia sekä ulomman lohkon yhtäsuuruusmerkin vasemmalla että oikealla puolella. Sen sijaan <code>let ... in</code>-lohko voi sitoa vain sillä puolella olevia tunnuksia, jolla lohko itse on määritelty. <a class="lahde" href="#lahteet">[Han06]</a> Yhtäsuuruusmerkin vasemmalla puolella olevien nimien sitomista tarvitaan logiikkaohjelmoinnissa.</p>

<p>Paikallisissa määrittelyissä muuttujien ja funktioiden välillä tehdään ero, ja ne evaluoidaan eri tavoin. Funktioiden evaluointi tapahtuu käyttämällä funktiota "sääntönä", jonka perusteella parametreina annetut muuttujat muutetaan uuteen muotoon. Paikallisesti määritellyt muuttujat eivät kuitenkaan käyttäydy kuten parametrittomat funktiot, sillä muuttujilla on yhteinen arvo. Esimerkissä 5 rivillä 4 määriteltävä parametriton funktio <code>x</code> evaluoidaan funktion tavoin: funktion <code>f</code> määrittely saa muodon <code>(coin,coin)</code>, ja sen mahdolliset arvot ovat <code>(0,0), (0,1), (1,0)</code> ja <code>(1,1)</code>. Funktiossa <code>g</code> paikallisesti määritelty muuttuja <code>x</code> peittää ulommassa lohkossa määritellyn samannimisen muuttujan. Kun funktiota <code>g</code> evaluoidaan, tämän muttujan <code>x</code> arvo on jo kiinnitetty, joten funktion mahdolliset arvot ovat vain <code>(0,0)</code> ja <code>(1,1)</code>. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 5. (Paikalliset muuttujat)</b><code><pre>
coin = 0
coin = 1

x = coin
f = (x,x)

g = (x,x) where x = coin
</pre></code></box>

<a name="arvojenkaytto" />
<h2>Arvojen käyttötavat</h2>

<p>Curry-ohjelmissa on mahdollista määritellä kahden tyyppisiä rakenteita: tietotyyppejä ja funktioita <a class="lahde" href="#lahteet">[AnH10]</a>. Sekä esimääriteltyihin että käyttäjän määrittelemiin tyyppeihin kuuluvat arvot, mukaanlukien funktiot, ovat ns. ensimmäisen luokan arvoja eli niitä voidaan sijoittaa muuttujaan, välittää parametreina, palauttaa funktion arvona ja ilmaista literaaleina.</p>

<p>Esimerkki 6 havainnollistaa funktioiden erilaisia käyttötapoja. Aluksi määritellään funktiot <code>kissa</code> ja <code>koira</code>. Funktio <code>kissa</code> sijoitetaan muuttujaan (joka on sekin oikeastaan parametriton funktio) <code>elain</code>. Funktio <code>aantele</code> ottaa parametrina funktion, jonka se suorittaa ja funktio <code>kumpi</code> palauttaa arvonaan funktion <code>kissa</code>, mikäli sille annettu kokonaislukuparametri ei ole jaollinen kahdella tai <code>koira</code>, jos se on. Funktiossa <code>main</code> kutsutaan edellä määriteltyjä funktioita. Ohjelman tulostus on: "miau" "hau" "miau".</p>

<box><b>Esimerkki 6. (Funktioiden käyttötapoja)</b><code><pre>
kissa = print "miau"
koira = print "hau"

elain = kissa

aantele x = x

kumpi i | i `mod` 2 /= 0  = kissa
        | otherwise       = koira

main = do
  elain
  aantele koira
  kumpi 7
</pre></code></box>

<p>Edellisten lisäksi on mahdollista määritellä nimettöimä funktioita, joita voidaan käyttää literaalien tavoin. Esimerkissä 7 on määritelty funktio <code>muotoile</code>, joka ottaa parametrinaan <code>muotoilija</code>-funktion ja sanalistan. Funktio käyttää parametrina saamaansa funktiota listan ensimmäisen sanan muotoilemiseen ja tulostaa sanan. Mikäli listassa on sanoja jäljellä, se kutsuu itseään rekursiivisesti. Funktion <code>main</code> ensimmäisellä rivillä kutsutaan <code>muotoilija</code>-funktiota parametrinaan esimääritelty <code>reverse</code>-funktio, joka kääntää parametrina saamansa sanan. Toisella rivillä annetaan funktiolle <code>muotoilija</code> parametrina funktioliteraali (tai nimetön funktio), joka ei tee sanoihin muutoksia.  Ohjelma tulostaa: "ieh" "amliaam" "hei" "maailma".</p>

<box><b>Esimerkki 7. (Merkkijonomuotoilija)</b><code><pre>
muotoile muotoilija (sana:sanat) | sanat == [] = print (muotoilija sana)
                                 | otherwise   = do
                                     print (muotoilija sana)
                                     muotoile muotoilija sanat

main = do
  muotoile reverse ["hei", "maailma"]
  muotoile (\x -> x) ["hei", "maailma"]
</pre></code></box>

<a name="sidontarekursiossa" />
<h2>Sidonta rekursiossa</h2>

<p>Kielissä, joissa funktiot ovat ensimmäisen luokan arvoja, on erotettavissa kaksi tapaa sitoa rekursiivisten kutsujen arvoja: syvä ja matala sidonta. Kysymys on siitä, minkä rekursiivisen version muuttujia parametrina välitetty funktio käsittelee. Curryssa sidonta on syvä eli parametrina välitetty funktio suoritetaan aina siinä ympäristössä, jossa se annetaan todellisena parametrina.</p>

<p>Esimerkissä 8 on muokattu kurssilla esitettyä esimerkkiä (<a href="http://www.cs.helsinki.fi/u/wikla/OKP/K11/materiaali/Deep.html">alkuperäinen esimerkki</a>) havainnollistamaan Curryn sidontakäytäntöä rekursiossa. Aluksi määritelty apufunktio <code>Q</code> ainoastaan kutsuu sille parametrina annettua funktiota. Funktio <code>A</code> ottaa parametrina kokonaisluvun <code>i</code> ja funktion <code>P</code>. Funktion <code>A</code> sisällä on <code>where</code>-lohkossa määritelty paikallinen funktio <code>B</code>, joka tulostaa muttujassa <code>i</code> olevan kokonaisluvun.</p>

<p>Kun funktiota <code>A</code> kutsutaan arvolla <code>1</code> ja funktiolla <code>C</code>, funktio kutsuu itseään rekursiivisesti arvoilla <code>2</code> ja <code>P</code>. Rekursiivisesti kutsuttu <code>A</code> kutsuu itseään uudelleen rekursiivisesti arvoilla <code>3</code> ja <code>B</code>. Rekursiivisesti kutsuttu <code>A</code> kutsuu nimellistä parametria <code>P</code>, joka oli edellisellä rekursiotasolla annettu todellisena parametrina. Koska funktio <code>B</code> annettiin todellisena parametrina, kun muuttujan <code>i</code> arvo oli <code>2</code> tulostaa ohjelma arvon <code>2</code>. Rekursiota purettaessa kutsutaan vielä jokaisella tasolla apufunktiota <code>Q</code>, jonka avulla tulostetaan muuttujan <code>i</code> arvo kullakin tasolla: <code>3 2 1</code>.</p>

<box><b>Esimerkki 8. (Sulkeuman sidonta rekursiossa)</b><code><pre>
Q P = P

A i P | i == 1    = do A 2 P
                       Q B
      | i == 2    = do A 3 B
                       Q B
      | otherwise = do P
                       Q B
  where B = print i

C = print "c"

main = do
  A 1 C
</pre></code></box>

<a name="etujajahaittoja3" />
<h2>Arvioita eduista ja haitoista</h2>

<p>Paikallisesti näkyvien funktioiden tarkoituksena on selkeyttää funktioiden määrittelyjä. Koska niitä ei ole tarkoitettu käytettäväksi kyseisten funktioiden ulkopuolelta, niiden näkyvyysalueen rajaaminen funktion sisälle tekee ohjelmoijan työstä helpompaa ja ohjelmakoodista selkeämpää.</p>

<p>Curryn käytäntö, jossa paikallisilla muuttujilla on yhteinen arvo, voi parantaa sekä ohjelman suorituskykyä että epädeterminististisiin funktioihin liittyviä laskelmia. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<!--********* 3. harjoitusviikko: *******-->
<hr />

<a name="ohjaus" />
<h1>Laskennan ohjaus</h1>

<p>Curry-ohjelmat koostuvat kahdenlaisista elementeistä: funktioista ja tietotyypeistä <a class="lahde" href="#lahteet">[AnH07]</a>. Esittelemme sauraavaksi erilaisia tapoja ohjata laskentaa funktioiden avulla. Tietotyyppejä käsitellään tarkemmin luvussa <a href="#tietotyypit">Perustietotyypit</a>.</p>

<a name="funktiot" />
<h2>Funktiot</h2>

<p>Curry-ohjelmassa funktioita voidaan määritellä käyttäen <b>hahmontunnistusta</b> (<i>pattern matching</i>). Hahmontunnistuksella tarkoitetaan sitä, että funktion tunnusta voidaan kuormittaa eriarvoisilla tai erimuotoisilla parametreilla ja käytettävä versio valitaan käyttäen hahmontunnistusta. Tyypillisesti hahmontunnistusta käytetään kuten esimerkissä 9. Esimerkissä on määritelty listan pituuden laskeva funktio. Jos parametrina annettu lista on tyhjä, sen pituus on nolla. Muussa tapauksessa lista alkaa jollakin alkiolla <code>_</code>, jota jatkaa lista <code>xs</code>. Tällöin listan pituus saadaan lisäämällä <code>1</code> rekursiivisesti lasketun listan <code>xs</code> pituuteen.<a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 9. (Listan pituus)</b><code><pre>
length []     = 0
length (_:xs) = 1 + length xs
</pre></code></box>

<p>Funktioiden määrittelyssä voidaan myös käyttää yhtä tai useampaa <b>ehtoa</b> (<i>condition</i>). Määrittelyn rakenne on seuraavanlainen: <a class="lahde" href="#lahteet">[AnH07]</a></p>

<pre>
<i>funktionTunnus muuttuja<sub>1</sub> ... muuttuja<sub>m</sub></i> <code>|</code> <i>ehto<sub>1</sub></i> <code>=</code> <i>lauseke<sub>1</sub></i>

                                <sub>&nbsp</sub>  <sub>&nbsp</sub>   <code>|</code>  ...<sub>&nbsp</sub> <code>=</code>   ...</i>
                                <sub>&nbsp</sub>  <sub>&nbsp</sub>   <code>|</code> <i>ehto<sub>n</sub></i> <code>=</code> <i>lauseke<sub>n</sub></i>

</pre>

<p>Ehdot ovat totuusarvoisia lausekkeita, jotka testataan tekstuaalisessa järjestyksessä. Funktion arvo määräytyy siitä lausekkeesta, jota vastaa ensimmäinen arvon <code>True</code> saava ehto. Viimeinen ehto voi olla myös <code>otherwise</code>, joka vastaa arvoa <code>True</code>. <a class="lahde" href="#lahteet">[AnH07]</a> Esimerkissä 10 on määritelty Fibonaccin lukuja laskeva funktio ehtojen avulla.</p>

<box><b>Esimerkki 10. (Fibonaccin lukuja ehto-funktiolla)</b><code><pre>

fib n | n==0      = 0
      | n==1      = 1
      | otherwise = fib (k-1) + fib (k-2)</pre></code></box>

<p>Monista muista kielistä poiketen Curryssa funktiot voivat olla <b>epädeterministisiä</b> (<i>non-deterministic</i>). Tämä tarkoittaa sitä, että funktio voi palauttaa eri arvoja samalla muuttujan arvolla. Tätä ominaisuutta on havainnollistettu esimerkissä 11. Esimerkkinä käytetään tehdasta, jossa työntekijöillä on kaksi tehtävää: leikata (<code>cut</code>) ja kiillottaa (<code>polish</code>). Työntekijöitä on kolme, mutta kuka tahansa ei voi tehdä mitä tahansa tehtävää. Epädeterministinen funktio <code>assign</code> kertoo, kenet on mahdollista määrätä mihinkin tehtävään: vain Alex ja Bert osaavat leikata ja vain Bert ja Chuck osaavat kiillottaa. Funktion <code>assign</code> avulla voidaan nyt määrätä kahden työntekijän tiimi, joista toinen osaa leikata ja toinen kiillottaa. Funktion <code>team</code> mahdolliset tulokset ovat <code>(Alex,Bert)</code>, <code>(Alex,Chuck)</code> ja <code>(Bert,Chuck)</code>. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 11. (Tehtaan työntekijät)</b><code><pre>
data task = cut | polish
data worker = Alex | Bert | Chuck

assign cut = Alex
assign cut = Bert
assign polish = Bert
assign polish = Chuck

team | x /= y = (x,y)
  where x = assign cut
        y = assign polish</pre></code></box>


<a name="operaattorit" />
<h2>Operaattorit</h2>

<p>Funktioita voidaan määritellä myös operaattoreina, jotka ovat kaksiparametrisia funktioita. Operaattori kirjoitetaan tavallisesti parametrien väliin, mutta sitä voi käyttää myös tavalliseen tapaan funktioiden edessä ympäröimällä sen suluilla. Operaattoreita määritellään käyttämällä avainsanoja <code>infix</code>, <code>infixl</code> ja <code>infixr</code>. Jokaisella operaattorilla on presedenssi, joka määritellään numeerisella parametrilla 0-9, ja assosiatiivisuus, joka määräytyy määrittelyyn käytetyn avainsanan perusteella. Formaalissa dokumentaatiossa määritellyt operaattorit ovat seuraavat: <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><code><pre>
infixl 9 !!
infixr 9 .
infixl 7 *, /, ‘div‘, ‘mod‘
infixl 6 +, -
infixr 5 ++, :
infix  4 =:=, ==, /=, <, >, <=, >=
infix  4 ‘elem‘, ‘notElem‘
infixr 3 &&
infixr 2 ||
infixl 1 >>, >>=
infixr 0 $, $!, $!!, $#, $##, ‘seq‘, &, &>, ?
</pre></code></box>

<p>Siis esimerkiksi <code>2+3*4</code> tulkitaan <code>2+(3*4)</code> ja <code>4-3-2</code> tulkitaan <code>(4-3)-2</code>. Jos operaattori on määritelty ilman assosiatiivisuutta, suoritusjärjestystä ei ole taattu.</p>

<a name="valinta" />
<h2>Valinta</h2>

<p>Suuri osa ohjelmissa tapahtuvasta valinnasta saadaan esitettyä funktiomäärittelyissä hahmontunnistuksen ja ehtojen avulla. Curry tarjoaa kuitenkin myös <code>if</code>-ehtolauseen ja <code>case</code>-valintalauseen.</p>

<p>Curryn ehtolause on todellisuudessa kolmeparametrinen funktio, mutta kieleen on lisätty syntaktista sokeria, jonka ansiosta lauseen yleinen muoto on seuraava: <a class="lahde" href="#lahteet">[AnH07]</a></p>

<pre><code>if</code> <i>ehto</i> <code>then</code> <i>lauseke<sub>1</sub></i> <code>else</code> <i>lauseke<sub>2</sub></i></pre>

<p>Myös <code>else</code>-haara on siis välttämätöntä määrittää. Esimerkissä 12 on näytetty, miten ehtolauseella voi määritellä yksinkertaisen funktion <code>not</code>, joka palauttaa totuusarvon negaation. On kuitenkin huomattava, että funktio <code>not</code> voidaan määrittää myös hahmontunnistuksen avulla, kuten esimerkissä 13 on tehty. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 12. (Totuusarvon negaatio - ehtolause)</b><code><pre>
not x = if x then False else True
&nbsp
</pre></code></box>

<box><b>Esimerkki 13. (Totuusarvon negaatio - hahmontunnistus)</b><code><pre>
not True = False
not False = True</pre></code></box>

<p>Valintalauseen yleinen muoto on seuraava: <a class="lahde" href="#lahteet">[Han06]</a></p>

<pre><code>case</code> <i>lauseke</i> <code>of</code>
  <i>hahmo<sub>1</sub></i> <code>-&gt</code> <i>lauseke<sub>1</sub></i>

  <code>...</code>
  <i>hahmo<sub>n</sub></i> <code>-&gt</code> <i>lauseke<sub>n</sub></i>
</pre>

<p>Valintalauseessa lopputulos valitaan hahmontunnistuksen avulla. Hahmot yritetään tunnistaa järjestykessä ylhäältä alas. Jos yhtäkään hahmoa ei tunnisteta, laskenta epäonnistuu. Valintalauseeseen loppuun voi lisätä oletusarvoisen tuloksen merkitsemällä hahmoa nimettömän muuttujan tunnuksella <code>_</code>. Esimerkki 14 havainnollistaa <code>case</code>-lauseen käyttöä. Siinä määritelty <code>swap</code>-funktio vaihtaa kaksialkioisen listan alkioiden paikkaa ja jättää muunlaiset listat muuttumattomiksi. <a class="lahde" href="#lahteet">[Han06]</a></p>

<box><b>Esimerkki 14. (Alkioiden vaihto)</b><code><pre>
swap z = case z of
  [x,y] -&gt [y,x]
  _     -&gt z</pre></code></box>

<a name="toisto" />
<h2>Toisto</h2>

<p>Curryssa ei ole sisäänrakennettua iteroivaa toistolausetta (kuten for- tai while-lauseet). Toistorakenteet toteutetaan rekursiivisten funktioiden avulla. Curryn toteutuksiin sisältyy useita valmiiksi toteutettuja toistorakenteisia funktiotia, kuten <code>until</code>, <code>filter</code> ja <code>iterate</code>. <a class="lahde" href="#lahteet">[Han06]</a></p>

<p>Funktio <code>until</code> käyttää funktiota <code>f</code> toistuvasti muuttujalle <code>x</code> kunnes ehto <code>p</code> täytyy. Funktion määrittely on seuraavanlainen: <a class="lahde" href="#lahteet">[Han06]</a></p>

<box>
<pre><code>until       :: (a -&gt Bool) -&gt (a -&gt a) -&gt a -&gt a
until p f x = if p x then x else until p f (f x)</code></pre>
</box>

<p>Funktio <code>filter</code> palauttaa sellaisen parametrina annetun listan osalistan, jonka kaikki alkiot täyttävät ehdon <code>p</code>. Funktion määrittely on seuraava: <a class="lahde" href="#lahteet">[Han06]</a></p>

<box><pre><code>
filter          :: (a -&gt Bool) -&gt [a] -&gt [a]
filter _ []     = []
filter p (x:xs) = if p x then x : filter p xs
                         else filter p xs
</code></pre></box>

<p>Funktio <code>iterate</code> palauttaa äärettömän listan, jonka alkiot saadaan käyttämällä funktiota <code>f</code> toistuvasti muuttujalle <code>x</code> eli <code>iterate f x = [x, f x, f (f x), ...]</code>. Funktio on määritelty seuraavasti: <a class="lahde" href="#lahteet">[Han06]</a></p>

<box><pre><code>
iterate     :: (a -&gt a) -&gt a -&gt [a]
iterate f x = x : iterate f (f x)
</code></pre></box>

<a name="rekursio" />
<h2>Rekursio</h2>

<p>Rekursio on keskeinen osa funktionaalista ohjelmointia. Äärettömien induktiivisesti määriteltyjen rakenteiden, kuten listojen, läpikäynti tapahtuu luonnollisimmin induktiivisesti rekursiolla. Listojen tapauksessa perusaskel käsittelee yleensä tyhjän listan <code>[]</code> ja induktioaskel käsittelee tapauksen <code>(x:xs)</code>, jossa esimerkiksi listan ensimmäiselle alkiolle <code>x</code> suoritetaan halutut operaatiot ja loppulistan <code>xs</code> käsittely tapahtuu rekursiivisesti.</p>

<p>Esimerkissä 15 on määritelty listan kääntävä funktio induktiivisesti. Tyhjän listan tapauksessa funktio palauttaa tyhjän listan, muuten funktio kääntää listan loppuosan rekursiivisesti ja lisää sen perään parametrina saamansa listan ensimmäisen alkion. Operaattori <code>++</code> konkatenoi kaksi listaa peräkkäin. Tällä tavalla toteutettu listan kääntäminen on kuitenkin pitkien listojen tapauksessa huomattavasti esimerkissä 3 (luvussa <a href="#nakyvyys">Tunnusten näkyvyysalueet</a>) esitettyä funktiota hitaampi. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 15. (Listan kääntäminen - hidas)</b><code><pre>
slowRev [] = []
slowRev (x:xs) = slowRev xs ++ [x]</pre></code></box>

<p>Rekursiivinen funktio käy läpi kaikki parametrina saamansa rakenteen alkiot. Jokaiselle alkiolle on mahdollista suorittaa operaatioita joko ennen rekursiivista kutsua, sen jälkeen tai sekä että. Tätä ominaisuutta voidaan käyttää hyväksi, kun operaation suorittamista varten tarvitaan jokin tieto koko alkiojukosta.</p>

<p>Esimerkiksi, jos halutaan vähentää listan pienin alkio jokaisesta listan alkiosta. Lista on käytävä läpi pienimmän alkion löytämiseksi ja uudestaan vähentämistä varten. Esimerkissä 16 näytetään, miten tämä voidaan tehdä käymällä lista läpi vain kerran. Funktion <code>submin</code> sisällä on määritelty rekursiivinen apufunktio <code>aux</code>, joka rekursioon laskeutuessaan antaa itselleen parametrina aina kyseessä olevasta alkiosta ja parametrina saamastaan alkiosta pienimmän. Kun rekursio loppuu eli kaikki alkiot on käyty läpi, funktio palauttaa löytämänsä pienimmän alkion, joka vähennetään jokaisella rekursiotasolla osalistan ensimmäisestä alkiosta ja välitetään eteenpäin muokatun osalistan kanssa. Funktio <code>min</code> palautaa parametreistaan pienemmän ja funktio <code>fst</code> parista ensimmäisen.</p>

<box><b>Esimerkki 16. (Listan pienimmän alkion vähentäminen jokaisesta alkiosta)</b><code><pre>

submin [] = []
submin (x:xs) = fst (aux (x:xs) x)
  where aux []     m = ([],m)
        aux (y:ys) m = let (zs,n) = aux ys (min y m)
                        in (y-n:zs,n)</pre></code></box>

<a name="etujajahaittoja4" />
<h2>Arvioita eduista ja haitoista</h2>

<p>Kuten esimerkeistä 12 ja 13 voidaan nähdä, funktiomäärittelyissä hahmontunnistus ja ehdot antavat mahdollisuuden selkeyttää ohjelmakoodia. Ehdolliset funktiomäärittelyt ovat keskeinen osa funktionaalista ohjelmointia, joten tällaisten usein esiinyvien rakenteiden selkeys on kriittistä koodin luettavuuden kannalta. Toisaalta <code>case</code>-lauseella pystytään huomattavasti selventämään sellaisten funktioiden määrittelyä, joissa valinta tehdään perustuen muuttujan hahmoon totuusarvoisen ominaisuuden sijaan.</p>

<p>Funktionaaliselle kielelle rekursio on monessa mielessä iteroivia lauseita luonnollisempi tapa toteuttaa toistorakenteita. Rekursiiviset funktiot ovat Curryssa helposti kirjoitettavissa ja luettavissa. Rekursiivisten rakenteiden sanotaan usein olevan suorituskyvyltään iteroivia rakenteita huonompia <a class="lahde" href="#lahteet">[Sco00]</a>. Rekursiivistenkin funktioiden suorituskyky riippuu kuitenkin hyvin paljon siitä, millä tavalla funktio toteutetaan <a class="lahde" href="#lahteet">[AnH07]</a>. Tehokkaiden rekursiivisten funktioiden toteuttaminen voi kuitenkin vaatia ohjelmointikielen toteutuksen melko syvällistäkin tuntemusta.</p>

<hr />
<a name="tietotyypit" />
<h1>Perustietotyypit</h1>

<p>Funktioiden lisäksi Curry-ohjelmissa tarvitaan erilaisia tietotyyppejä. Esittelemme seuraavaksi tarkemmin luvussa <a href="#alkiorakenne">Alkiorakenne</a> esitellyt perustietotyypit ja tarkastelemme niiden toteutusta ja käyttöä.</p>

<a name="alkeistyypit" />
<h2>Alkeistyypit</h2>

<p>Alkeistyypit ovat Curryn formaalissa dokumentaatiossa määriteltyjä niin sanottuja literaaleja.</p>

<h3>Kokonaisluvut</h3>

<p>Curryn formaali spesifikaatio ei määrittele kokonaisluvuille (<code>Int</code>) kiinnitettyjä arvoalueita. Eri toteutukset toteuttavat ne eri tavoin. Esimerkiksi PACKS:issa kokonaislukuoperaatiot on muutamaa poikkeusta lukuunottamatta toteutettu siten, että kokonaislukujen tarkkuus voi vaihdella <a class="lahde" href="#lahteet">[Han11b]</a>. Sen sijaan MCC tukee vain määrätyn pituisia kokonaislukuja, joiden suurimman ja pienimmän arvon voi selvittää Integer-moduulin funktioilla <code>minInt</code> ja <code>maxInt</code> <a class="lahde" href="#lahteet">[Lux11]</a>.</p>

<p>Tavalliset kokonaisluvuille määritellyt operaatiot, kuten yhteen- ja kertolasku on määritelty vain kokonaislukujen välille <a class="lahde" href="#lahteet">[Han06]</a>. Esimerkiksi kokonaislukuja ja liukulukuja ei siis voi laskea yhteen ilman erillistä tyyppimuunnosta.</p>

<h3>Merkit</h3>

<p>Merkkien (<char>Char</char>) literaalivakiot esitetään yksinkertaisilla heittomerkeillä (<code>'</code>) ympäröitynä kuten Javassa. Erikoismerkkien eteen on laitettava kenoviiva (<code>\</code>) esimerkiksi rivinvaihtoa merkitään <code>'\n'</code> ja merkkiä <code>'ä'</code> voidaan merkitä myös kyseisen merkin ASCII arvon 228 avulla <code>'\228'</code>. <a class="lahde" href="#lahteet">[Han06]</a></p>

<p>Merkkien ja niiden ASCII arvojen välille on formaalissa dokumentaatiossa määritelty muunnosfunktiot <code>ord :: Char -&gt Int</code> ja <code>chr :: Int -&gt Char</code> <a class="lahde" href="#lahteet">[Han06]</a>. Curryn toteutukset sisältävät merkeille myös useita muita hyödyllisiä funktiota, esimerkiksi totuusarvoiset <code>isUpper</code> ja <code>isDigit</code> sekä muunnosfunktiot <code>toUpper</code> ja <code>digitToInt</code> <a class="lahde" href="#lahteet">[Han11b]</a>.</p>

<h3>Merkkijonot</h3>

<p>Merkkijonot (<code>String</code>) ovat Curryssa merkkien listoja (<code>[Char]</code>). Merkkijonoja voidaan kuitenkin esittää literaaleilla lainausmerkeillä (<code>"</code>) ympäröitynä. Siis esimerkiksi <code>"hei"</code> on sama asia kuin <code>['h', 'e', 'i']</code>. <a class="lahde" href="#lahteet">[Han06]</a></p>

<p>Formaalissa dokumentaatiossa on määritelyt merkkijonofunktio <code>show :: a -&gt String</code>, joka esittää minkä tahansa tyyppisen termin merkkijonona <a class="lahde" href="#lahteet">[Han06]</a>. Lisäksi, koska merkkijonot ovat vain merkkien listoja, kaikki listoille määritellyt operaatiot ovat suoraan käytettävissä myös merkkijonoille. Esimerkiksi voimme katenoida kaksi merkkijonoa peräkkäin operaattorilla <code>++</code> tai kääntää merkkijonon funktiolla reverse: koodi <code>"Hei" ++ "Hoi"</code> tuottaa merkkijonon <code>"HeiHoi"</code> ja koodi <code>reverse "Hei maailma"</code> antaa tuloksen <code>"amliaam ieH"</code>. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<h3>Liukuluvut</h3>

<p>Liukulukujen (<code>Float</code>) kokonais- ja desimaaliosa erotetaan toisistaan pisteellä. Myös eksponenttimerkintä, esim. <code>5.0e-4</code>, joka vastaa liukulukua <code>0.0005</code> on sallittu.</p>

<p>Koska kuormittaminen ei ole Curryn forttaa dokumentaation perusteella mahdollista, liukulukujen tavallisten operaatioiden, kuten laskutoimitusten, tunnukset eivät ole samat kuin kokonaisluvuilla <a class="lahde" href="#lahteet">[Han06]</a>. Esimerkiksi PACKS:ssa ja MCC:ssa liukulukujen tavallistet laskutoimitukset ja järjestystä testaavat operaattorit on erotettu kokonaislukuoperaatioista pisteellä <a class="lahde" href="#lahteet">[Han11b; Lux11]</a>. Liukulukujen yhteenlasku tapahtuu siis koodilla <code>2.3 +. 3.2</code>, mikä tuottaa tuloksen <code>5.5</code>.</p>

<a name="perustyypit" />
<h2>Perustyypit</h2>

<p>Perustyypit ovat muita Curryn toteutuksissa esimääritettyjä tyyppejä.</p>

<h3>Totuusarvot</h3>

<p>Totuusarvot (<code>Bool</code>) on määritelty seuraavasti:</p>

<box><pre><code>

data Bool = True | False
</code></pre></box>

<p>Totuusarvoille on Curryn formaalissa dokumentaatiossa esimääritelty operaattorit <code>&&</code> ja <code>||</code> sekä funktiot <code>not</code> ja <code>if_then_else</code>. Ehtolauseke <code>if b then x else y</code> on siis vain syntaktista sokeria, joka tarkoittaa lauseketta <code>(if_then_else b x y)</code>. <a class="lahde" href="#lahteet">[Han06]</a></p>

<h3>Onnistuminen</h3>

<p>Tyyppiä <code>Success</code>, jonka olemme tässä suomentaneet onnistumiseksi, käytetään ilmaisemaan onnistuneesti ratkaistua ehtoa. Vastaavasti symboli <code>success</code> tarkoittaa ehtoa, jonka ratkaiseminen onnistuu aina. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Esimääriteltyjä operaattoreita ovat rajoittava yhtsuuruus <code>=:=</code>, rinnakkainen konjunktio <code>&</code> ja rajoittava lauseke <code>&></code>. Näiden avulla saadaan muodostettua tavallisia yhtälöehtoja, jonka ratkaisuja voidaan etsiä. Esimerkiksi koodi <code>x*x =:= y & x =:= 2 where x,y free</code> tuottaa tuloksen <code>{x = 2, y = 4}</code>. <a class="lahde" href="#lahteet">[Han06]</a></p>

<h3>Yksikkö</h3>

<p>Symbolilla <code>()</code> merkitään sekä tyyppiä yksikkö (<i>Unit</i>) että ainutta arvoa, jonka tämä tyyppi voi saada. Yksikkö-tyyppi on analoginen Javan tyypin <code>void</code> kanssa. Sitä käytetään funktioissa, joiden palautusarvo on epäoleellinen.</p>

<a name="kokoelmatyypit" />
<h2>Kokoelmatyypit</h2>

<h3>Listat</h3>

<p>Tyyppiä <code>T</code> olevia alkioita sisältävä lista (<code>[T]</code>) on joko tyhjä lista (<code>[]</code>) tai se koostuu ensimmäisestä alkiosta, tyyppiä <code>T</code> olevasta arvosta <code>x</code>, jota seuraa loppulista, tyyppiä <code>[T]</code> oleva arvo <code>xs</code>, jolloin kirjoitetaan <code>x:xs</code>. Kirjoittamisen helpottamiseksi lista <code>u:v:w:[]</code> voidaan esittää myös literaalina <code>[u,v,w]</code>. Lisäksi kokonaislukujen listoja voidaa määritellä erillisen väli-notaation (<i>range</i>) avulla. Äärellinen lista saadaan notaatiolla <code>[<i>e<sub>1</sub></i> .. <i>e<sub>2</sub></i>]</code> ja ääretön lista notaatiolla <code>[<i>e<sub>1</sub></i> .. ]</code>. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Listat ovat yksi funktionaalisen ohjelmoinnin tärkeimmistä tyypeistä, ja niille onkin  suuri joukko esimääriteltyjä funktioita. Esimerkiksi seuraavat funktiot on määritelty Curryn formaalissa dokumentaatiossa (operaattorit on määritelty suluissa):</p>

<box>
<table>
<tr><th>Funktio</th><th>Kuvaus</th></tr>

<tr valign="top"><td><code>head :: [a] -&gt a</code></td><td>Palauttaa listan ensimmäisen alkion.</td></tr>

<tr valign="top"><td><code>tail :: [a] -&gt [a]</code></td><td>Palauttaa listan ilman sen ensimmäistä alkiota.</td></tr>

<tr valign="top"><td><code>null :: [_] -&gt Bool</code></td><td>Keroo, onko lista tyhjä.</td></tr>

<tr valign="top"><td><code>(++) :: [a] -&gt [a] -&gt [a]</code></td><td>Konkatenoi kaksi listaa peräkkäin.</td></tr>

<tr valign="top"><td><code>length :: [a] -&gt Int</code></td><td>Kertoo listan alkioiden lukumäärän.</td></tr>

<tr valign="top"><td><code>(!!) :: [a] -&gt Int -&gt a</code></td><td>Palauttaa sen listan alkion, joka on parametrina annetussa kohdassa (indeksi). Ensimmäisen alkion indeksi on 0.</td></tr>

<tr valign="top"><td><code>map :: (a -&gt b) -&gt [a] -&gt [b]</code></td><td>Kuvaa kaikki listan alkiot annetulla funktiolla.</td></tr>

<tr valign="top"><td><code>filter :: (a -&gt Bool) -&gt [a] -&gt [a]</code></td><td>Palauttaa ne listan alkiot, jota täyttävät annetun ehdon.</td></tr>

<tr valign="top"><td><code>repeat :: a  -&gt [a]</code></td><td>Palauttaa äärettömän listan, jonka kaikki alkiot ovat samanarvoisia kun parametrina saatu alkio.</td></tr>

</table>
</box> 

<h3>Tuppelit</h3>

<p>Tuppeli (<code>(t<sub>1</sub>, ..., t<sub>n</sub>)</code>) on määrätyn pituinen jono mahdollisesti eri tyyppisiä alkioita <a class="lahde" href="#lahteet">[AnH07]</a>. Lista ja tuppeli eroavat siis toisistaan kahdella tavalla: lista voi olla äärettön, kun tuppeli sisältää aina tietyn äärellisen määrän alkioita, toisaalta kaikki listan alkiot ovat saman tyyppisiä, kun taas tuppeli voi sisältää useita eri tyyppisiä alkioita.</p>

<p>Tuppeleita käytetään esimerkiksi, kun funktion halutaan palauttavan useita arvoja. Formaalissa dokumentaatiossa vain parille <code>(a,b)</code> on esimääriteltyjä funktioita: <code>fst</code> palauttaa parin ensimmäisen alkion ja <code>snd</code> palauttaa parin toisen alkion.</p>

<a name="tyypitys" />
<h2>Tyypitys</h2>

<p>Curry on vahvasti tyypitetty kieli, joka käyttää monimuotoista tyyppijärjestelmää (<i>polymorphic type system) </i> <a class="lahde" href="#lahteet">[DaM82]</a>. Tämä tarkoittaa sitä, että arvoille ei tarvitse määritellä yksiselitteistä tyyppiä, vaan tyyppeihin voi jättää <i>vapaita tyyppimuuttujia</i>, joiden paikalla kääntäjä tarvittaessa päättelee yksikäsitteisen tyypin <a class="lahde" href="#lahteet">[Han06]</a>. Esimerkiksi edellä esitetyt listoja käsittelevät funktiot käyttävät vapaina tyyppimuuttujina nimiä <code>a</code> ja <code>b</code>.</p>

<p>Itse asiassa arvolle ei ole edes pakko eksplisiittisesti määritellä tyyppiä. Curryssä on ominaisuus nimeltä tyyppipäättely (<i>type inference</i>), jonka ansiosta kääntäjä osaaa päätellä annetun lausekkeen tyypin. Yleisesti ottaen pidetään kuitenkin hyvänä käytäntönä, että funktioiden tyypit kerrotaan ohjelmakoodissa eksplisiittisesti.</p>


<a name="etujajahaittoja5" />
<h2>Arvioita eduista ja haitoista</h2>

<p>Javaan tottuneen ohjelmoijan kannalta on helpottavaa, että merkkien esitystapa on Curryssa valittu samanlaiseksi. Merkkijonojen esittäminen merkkien listoina on sekä intuitiivista että joustavaa, koska listoille määriteltyjä funktiota voidaan käyttää suoraan myös merkkijonojen tutkimiseen ja muokkaamiseen.</p>

<p>Liukulukuoperaattorit puolestaan ovat hyvin epäintuitiivisia ja ainakin PACKS:issa ja MCC:ssa valitun esitystavan ainakin matemaatikko yhdistäisi ennemmin matriiseihin kuin liukulukuihin. Lisäksi ainakin MCC-toteutuksessa liukulukuoperaatiot näyttävät tuottavan helposti erittäin epätarkkoja tuloksia, esimerkiksi <code>1.23 +. 4.56</code> antaa tuloksen <code>5.789999999999999</code>.</p>

<hr />
<!-- ********* 4. harjoitusviikko: ******* -->

<a name="laskennankapselointi" />
<h1>Laskennan kapselointi</h1>

<p>Tarkastelemme tässä luvussa, millä tavalla toiminnaliisuuksia voidaan abstrahoida käyttämällä nimettyjä aliohjelmia ja millä tavalla niistä voidaan rakentaa uusia toiminnallisuuksia. Lisäksi esittelemme suoritusaikaisiin virheisiin varautumisen välineitä ja tyypillisiä ohjelma-arkkitehtuureja. Käsittelemme myös rinnakkaislaskentaa.</p>

<a name="aliohjelmat" />
<h2>Aliohjelmat</h2>

<h3>Proseduurit ja funktiot</h3>

<p>Curryn laiskan evaluaation ja sivuvaikutusten puuttumisen takia vuorovaikutteiset proseduurit on erotettava tavallisista funktioista <a class="lahde" href="#lahteet">[AnH07]</a>. Tämä tapahtuu funktion tyypin perusteella.</p>

<p>Tavallisen funktion tyyppi on muotoa <code>a -&gt b</code> joillekin tyypeille <code>a</code>, <code>b</code>. Siis tyyppiä <code>a -&gt b</code> oleva funktio kuvaa tyypin <code>a</code> arvoja tyypin <code>b</code> arvoille.</p>

<p>Proseduurin ajatellaan olevan sarja toimintoja, jotka muuttava maailman tilaa. Parametrittoman proseduurin tyyppi on <code>IO a</code> jollekin tyypille <code>a</code>, minkä voidaan ajatella olevan lyhenne tyypille <code>World -&gt (a,World)</code>. Proseduuri on siis funktio, joka saa parametrikseen maailman tilan, suorittaa sille I/O-toimintoja, ja palauttaa maailman uuden tilan sekä tyyppiä <code>a</code> olevan arvon. <a class="lahde" href="#lahteet">[AnH07]</a> Proseduurin, joka ottaa tyyppiä <code>b</code> ja <code>c</code> olevat parametrit ja palauttaa tyyppiä a olevan arvon, tyyppi on <code>b -&gt c -&gt IO a</code>. Parametreja ottava proseduuri mallinnetaan siis funktiona, joka ottaa parametreja ja palauttaa parametrittoman proseduurin.</p>

<p>Curryssa I/O-proseduurien on oltava hyvinmääriteltyjä, joten epädeterminismi ei niissä ole sallittua <a class="lahde" href="#lahteet">[AnH07]</a>.</p>

<h3>Aliohjelmien abstrahointi</h3>

<p>Funktiot ja proseduurit ovat ensimmäisen luokan arvoja. Niitä voi sitoa nimiin ja sen jälkeen käsitellä kuten mitä tahansa muitakin arvoja. Niitä voi siis antaa ja palauttaa funktioden parametreina ja käyttää osana muita funktiota ja proseduureja.</p>

<p>Curry-totetutuksissa on esimääritelty operaattori <code>(&gt&gt=) :: IO a -&gt (a -&gt IO b) -&gt IO b</code>, joka ottaa parametreinaan parametrittoman I/O-proseduurin ja I/O-proseduurin, joka saa parametrikseen ensimmäsen proseduurin palauttaman arvon. Yhdistämisessä saadun proseduurin tyyppi on <code>IO b</code>. Esimerkissä 17 operaattoria <code>&gt&gt=</code> käytetään kahden esimääritellyn proseduurin yhdistämiseen. Tuloksena on tyyppiä <code>IO ()</code> oleva funktio, jota merkitään tunnuksella <code>main</code>. Kun <code>main</code> suoritetaan, ohjelma lukee merkin standardisyöttövirrasta ja tulostaa sen standarditulostusvirtaan. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 17. (I/O-proseduurien yhdistäminen)</b><code><pre>
main = getChar >>= putChar</pre></code></box>

<p>Vastaavasti operaattori <code>(&gt&gt) :: IO a -&gt IO b -&gt IO b</code> suorittaa parametreina saamansa I/O-proseduurit järjestyksessä, mutta jättää ensimmäisenä suoritetun proseduurin palauttaman arvon käyttämättä. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<p>Hyödyllisiä esimääriteltyjä I/O-proseduureja ovat myös <code>return</code>, joka vain palauttaa parametrina saamansa arvon muuttamatta maailman tilaa ja <code>done</code>, joka ei palauta mitään: <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><code><pre>
return :: a -&gt IO a
&nbsp
</pre></code></box>
<box><code><pre>
done :: IO ()
done = return ()</pre></code></box>

<a name="parametrinvalitys" />
<h2>Parametrinvälitys</h2>

<p>Curry välittää parametrit arvoparametreina. Esimerkin 18 ohjelma demonstroi Curryn parametrinvälitystä. Pääohjelma välittää funktiolle <code>p</code> parametrin <code>x</code>, jonka arvo on True. Koska kyseessä on arvoparametri, funktio <code>p</code> ei pääse muuttamaan parametrin arvoa, ja ohjelma tulostaa <code>True</code> kaksi kertaa.</p>

<box><b>Esimerkki 18. (Parametrinvälitys)</b><pre><code>x = True

p y = let y = False in do
  print x

main = do
  p x
  print x</code></pre></box>

<a name="virheisiinvarautuminen" />
<h2>Virheisiin varautuminen</h2>

<p>Virheisiin varaudutaan Curryssa käyttämällä syötettä tutkivia funktioita. Alla on listattu joukko esimääriteltyjä funktioita ja kirjastofunktioita, joita voidaan käyttää tähän tarkoitukseen: <a class="lahde" href="#lahteet">[Han06; Han11b]</a> </p>

<box>
<table>
<tr><th>Funktio</th><th>Kuvaus</th></tr>

<tr valign="top"><td><code>null :: [_] -&gt Bool</code></td><td>Selvittää, onko lista tyhjä.</td></tr>

<tr valign="top"><td><code>length :: [a] -&gt Int</code></td><td>Palauttaa listan pituuden.</td></tr>

<tr valign="top"><td><code>any :: (a -&gt Bool) -&gt [a] -&gt Bool</code></td><td>Selvittää, löytyykö listasta yhtään alkiota, joka täyttää parametrina annetun ehdon.</td></tr>

<tr valign="top"><td><code>all :: (a -&gt Bool) -&gt [a] -&gt Bool</code></td><td>Selvittää, täyttävätkö kaikki listan alkiot parametrina annetun ehdon.</td></tr>

<tr valign="top"><td><code>elem :: a -&gt [a] -&gt Bool</code></td><td>Selvittää, löytyykö parametrina annettu alkio listasta.</td></tr>

<tr valign="top"><td><code>isUpper :: Char -&gt Bool</code></td><td>Selvittää, onko merkki iso kirjain.</td></tr>

<tr valign="top"><td><code>isLower :: Char -&gt Bool</code></td><td>Selvittää, onko merkki pieni kirjain.</td></tr>

<tr valign="top"><td><code>isAlpha :: Char -&gt Bool</code></td><td>Selvittää, onko merkki kirjain.</td></tr>

<tr valign="top"><td><code>isDigit :: Char -&gt Bool</code></td><td>Selvittää, onko merkki numero.</td></tr>

<tr valign="top"><td><code>isSpace :: Char -&gt Bool</code></td><td>Selvittää, onko merkki välilyönti (<i>whitespace</i>).</td></tr>

</table>
</box> 


<p
>Lisäksi virheisiin varaudutaan tyyppien avulla. Funktio joka laskee tyypin <code
  >a</code
  > arvosta tyypin <code
  >b</code
  > arvon mutta voi törmätä virheeseen ja olla laskematta mitään, on tyyppiä <code
  >a -&gt; Maybe b</code
  >. Funktio, joka lisäksi virhetilanteessa palauttaa virheviestin, on tyyppiä <code
  >a -&gt; Either String a</code
  >. Jonkun arvon laskennan virhealttius näkyy siis sen tyypissä: esim<code
  >Maybe Double</code
  > -tyyppiä oleva arvo on <code
  >Double</code
  >-tyypin arvo jonka laskennassa voi tapahtua virhe niin ettei arvoa olekaan.</p
><p
>Virheen jota on mahdotonta käsitellä ja joka ei näy tyyppitasolla voi luoda funktiolla <code
  >error :: String -&gt; a</code
  >. Lausekkeen <code
  >error &quot;:D&quot;</code
  > evaluointi lopettaa ohjelman tulostaen <code
  >:D</code
  >.</p
>

<a name="ohjelmanrakenne" />
<h2>Curry-ohjelman rakenne</h2>

<h3>Proseduurit</h3>
<p>Interaktiiviset Curry-ohjelmat voidaan kirjoittaa edellä esitetyn <code>(&gt&gt=)</code>-operaattorin avulla. Tämän käyttö kuitenkin johtaa helposti hyvin epäselvään koodiin. Esimerkin 19 ohjelma kopioi kaikki merkit standardisyöttövirran merkit standarditulostusvirtaan ensimmäiseen pisteeseen saakka. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 19. (Kopiointi - yhdistämällä I/O-proseduureja)</b><pre><code>
echo = getChar &gt&gt= \c -&gt if c == '.' then done else putChar c &gt&gt echo</code></pre></box>

<p>Ohjelmakoodin selkeyttämiseksi Curry tarjoaa proseduurien määrittelemiseen erityisen <code>do</code>-lohkon. Tämän lohkon sisällä peräkkäisten toimintojen kirjoittamiseen käytetään erottimina samanlaisia sisennyksiä kun muissakin lohkorakenteissa. Edellinen ohjelma voidaan siis kirjoittaa kuten esimerkissä 20. <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><b>Esimerkki 20. (Kopiointi - do-lohko)</b><pre><code>
echo = do c &lt- getChar
          if c == '.'
            then done
            else do putChar c
                    echo</code></pre></box>
                    
<h3>Moduulit</h3>

<p>Curry-ohjelma voi olla jakautunut useaan moduuliin, jotka määritellään avainsanalla <code>module</code>. Curry-moduuli koostuu joukosta datatyyppi-, funktio- ja proseduurimääritelmiä. Erityisessä asemassa on moduuli, joka määrittää <code>IO ()</code>-tyyppisen arvon tunnukselle <code>main</code>. Tämä on se proseduuri jonka lopullinen käännetty ohjelma suorittaa. Kuten lauseke, myös moduuli voi sisältää ulospäin näkymättömiä määritelmiä.</p>

<p>Jokainen moduuli <code>M</code> on tallennettava tiedostoon, joka nimi on <code>M.curry</code>. Ohjelman on sisällettävä yksi päämoduuli, joka eksplisiittisesti tuo muut ohjelman käyttämät moduulit käyttämällä avainsanaa <code>import</code>. Jokainen moduuli alkaa otsikolla <code>module M where</code>. Jos otsikkoa ei ole eksplisiittisesti kirjoittettu, se lisätään implisiittisesti tiedoston nimen perusteella.</p>

<p>Mikäli moduulin otsikkoon ei ole lisätty rajoituksia, kaikki moduulin sisältämät datatyyppi-, funktio- ja proseduurimääritelmät ovat muiden moduulien käytössä. Muista moduuleista tuotuja määritelmiä ei kuitenkaan välitetä eteenpäin. Mikäli näkyvyyttä halutaan rajoittaa, on otsikossa eksplisiittisesti ilmoitettava ne määritelmät, jotka ovat muiden moduulien käytössä. Tämä tehdään lisäämällä moduulin nimen perään pilkuilla erotettu lista nimettyjä määrittelyjä, esimerkiksi <code>module Stack(stackType, push, pop, newStack) where ...</code>.</p>



<a name="rinnakkaislaskenta" />
<h2>Rinnakkainen laskenta</h2>

<p>Deklaratiivisena kielenä Curry tukee rinnakkaista laskentaa erinomaisesti <a class="lahde" href="#lahteet">[Han99]</a>. Curryssa I/O-proseduurien sisältämien toimintojen ja assosiatiivisten operaattoreiden järjestys on määritelty. Muu laskenta tapahtuu määrittelemättömässä järjestyksessä, joten se on mahdollista toteuttaa rinnakkaisesti. Käytännössä rinnakkaisuutta on toteutettu esimerkiksi Javan säikeiden avulla <a class="lahde" href="#lahteet">[Han11a, Curry2Java]</a>. Rinnakkaisuuden käyttäminen riippuu kuitenkin täysin toteutuksesta. Curry-ohjelmien sisällä ei ole mahdollista esimerkiksi luoda säikeitä.</p>

<p
>Tutkitaan esimerkiksi operaattorin <code>&amp;</code> tulkintaa. Rajoiteessa <code>c_1 &amp; c_2</code> ehdot <code>c_1</code> ja <code>c_2</code> tulkitaan rinnakkain. Ehdon <code>c_1</code> tulkinta voi seisahtua, kun ehdon <code>c_2</code> tulkinta jatkuu, ja alkaa uudestaan, jos ehdon <code>c_1</code> tulkinnassa löydetään jotain, joka mahdollistaa sen. Peräkkäisen tulkinnan voi pakottaa operaattorilla <code>&amp;&gt;</code>.</p>

<a name="etujajahaittoja6" />
<h2>Arvioita eduista ja haitoista</h2>

<p>Curryn parametrinvälitystavasta seuraa että aliohjelman kutsuminen ei voi muuttaa kyseisen aliohjelman ulkopuolisia sidontoja. Tätä voi pitää etuna koska ohjelmoijan ei tarvitse pitää mielessä minkä nimisiä paikallisia muuttujia aliohjelman sisällä käytetään.</p>

<p>Proseduurien ja funktioden erottaminen toisistaan tyyppitasolla on myös etu. Unohtaakseen että käyttämällään aliohjelmalla on sivuvaikutuksia, ohjelmoijan pitäisi erehtyä sen tyypistä. Huomatessaan että aliohjelman tyyppi kertoo sen olevan funktio, ei proseduuri, ohjelmoija voi olla varma että sillä ei ole sivuvaikutuksia. </p>

<hr />
<!--********* 5. harjoitusviikko: *******-->

<a name="datankapselointi" />
<h1>Datan kapselointi</h1>

<p>Tarkastellaan, millä tavalla käyttäjä voi määritellä tietotyyppejä ja millaisten tyyppien määrittäminen on mahdollista.</p>

<a name="tietotyyppienmaar" />
<h2>Tietotyyppien määrittäminen</h2>

<p>Jotkut Curryn toteutuksissa esimääritellyt tietotyypit ovat primitiivisiä, mutta monet on määritelty <code>data</code>-lauseella. Esimerkkeinä tällaisista tietorakenteista ovat <code>Maybe</code> ja <code>Either</code>, jotka on määritelty seuraavasti: <a class="lahde" href="#lahteet">[AnH07]</a></p>

<box><pre><code>
data Maybe a = Nothing | Just a

data Either a b = Left a | Right b
</code></pre></box>

<p>Siis tyyppiä <code>Maybe</code> oleva muuttuja voi saada arvokseen <code>Nothing</code> tai <code>Just a</code>, missä <code>a</code> on tyyppiparametri. Listoissa ja tuppeleissakin on primitiivistä vain niiden syntaktinen sokeri. Esimerkiksi listojen voidaan ajatella olevan esimääritelty lauseella <code>data [a] = [] | a : [a]</code>. <a class="lahde" href="#lahteet">[AnH07]</a> Myös käyttäjä voi määritellä tietotyyppejä vastaavalla tavalla.</p>

<p>Yleisesti tietotyypin esittely tapahtuu konstruktorilauseella:</p>

<pre>
<code>data</code> <i>T a<sub>1</sub> ... a<sub>n</sub></i><code> = </code><i>C<sub>1</sub> t<sub>11</sub> ... t<sub>1n<sub>1</sub></sub></i><code> | ... | </code><i>C<sub>k</sub> t<sub>k1</sub> ... t<sub>kn<sub>k</sub></sub></i>

</pre>

<p>Tämä lause määrittää <em>tyyppikonstruktorin</em> <i>T</i> ja <i>k</i> <em>datakonstruktoria</em> <i>C<sub>1</sub>, ..., C<sub>k</sub></i>, joista kukin on tyyppiä <i>t<sub>i1</sub></i><code> -> ... -> </code><i>t<sub>in<sub>i</sub></sub></i><code> -> </code><i>T</i><code></code><i>a<sub>1</sub></i><code> ... </code><i>a<sub>n</sub></i>,
missä <i>i</i> = <i>1</i>, ..., <i>k</i>. <a class="lahde" href="#lahteet">[Han06]</a> Datakonstruktorilla on siis funktiotyyppi jos <code>n<sub>i</sub></code>>0.</p>


<p>Esimerkissä 21 määritellään tyyppi <code>BTree a</code>, jonka jäseniä ovat binääripuut joiden solmut ja lehdet sisältävät tyyppiä <code>a</code> olevia arvoja. Esimerkiksi <code>Fork &quot;a&quot; (Leaf &quot;b&quot;) (Fork &quot;c&quot; (Leaf &quot;:D&quot;) (Leaf &quot;:E&quot;))</code> on <code>String</code>-tyypin arvoja sisältävä binääripuu jossa on kaksi solmua ja kolme lehteä.</p>

<box><b>Esimerkki 21. (Binääripuu)</b><pre><code>data BTree a = Fork a (BTree a) (BTree a) | Leaf a
</code></pre></box>

<p>Binääripuun määritelmässä määritellään tyyppikonstruktori <code>BTree</code>, joka ottaa tyyppiparametrin <code>a</code>. Tyyppikonstruktorille <code>BTree a</code> määritellään kaksi datakonstruktoria: <code>Fork</code> ja <code>Leaf</code>. Konstruktori <code>Fork</code> ottaa parametrina arvon, joka on tyyppiä <code>a</code>, ja kaksi arvoa, jotka ovat tyyppiä <code>BTree a</code>. Konstruktori <code>Leaf</code> ottaa yhden arvon joka on tyyppiä <code>a</code>. Datakonstruktori <code>Fork</code> on tyyppiä <code>a -&gt; BTree a -&gt; BTree a -&gt; BTree a</code> ja <code>Leaf</code> on tyyppiä <code>a -&gt; BTree a</code>.</p>

<p>Voimme määritellä myös yleisemmän puun, ns. ruusupuun (<em>rose tree</em>), jossa solmun lapsien määrä on rajoittamaton, ja nollalapsinen solmu toimii lehtenä. Tämä on tehty esimerkissä 22 käyttäen määrittelyssä listaa, joka sisältää kaikki solmun alipuut.</p>

<box><b>Esimerkki 22. (Ruusupuu)</b><pre><code>
data RTree a = RFork a [RTree a]
</code></pre></box>

<p>Esimerkissä 23 on määritelty tyyppi <code>Expression</code>, jonka jäseniä ovat yhteenlaskusta, kertolaskusta, negaatiosta, kokonaislukuvakioista ja muuttujista koostuvat lausekkeet. Esimerkiksi lauseketta y*(2-x) edustaa <code>Times (Variable &quot;y&quot;) (Plus (Constant 2) (Negate (Variable &quot;x&quot;)))</code>.</p>

<box><b>Esimerkki 23. (Lauseke)</b><pre><code>
data Expression =
  Plus Expression Expression 
  | Times Expression Expression 
  | Negate Expression
  | Constant Int
  | Variable String
</code></pre></box>

<a name="olioohjelmoinnista" />
<h2>Olio-ohjelmoinnista</h2>

<p>Curryssä ei ole olioita tai luokkia tai juuri mitään niihin verrattavaa. Tämä johtuu siitä, että Curryssä ei käytetä abstraktiotekniikoita joissa data paritetaan sitä manipuloivien funktioden ja proseduurien kanssa yhdeksi kokonaisuudeksi, vaan edellämainitut pidetään erillään.</p>

<a name="etujajahaittoja7" />
<h2>Arvioita eduista ja haitoista</h2>

<p>Konstruktorilause <code>data</code> on tyyliltään algebrallinen ja deklaratiivinen ja lukijan kannalta sekä hyvin selkeä että hyvin tiivis. Ylläolevien esimerkkien toteuttaminen esimerkiksi Javalla olisi verraten työlästä.</p>

<hr />
<!---********* Julkinen <i>Grande Finale</i> luennolla 28.4.: *******-->

<a name="yhteenveto" />
<h1>Yhteenveto</h1>
<p>Kuten harva muu kieli, Curry on sekä puhtaasti funktionaalinen että logiikkaohjelmointikieli. Täten se loistaa käyttötarkoituksissa, jotka hyötyvät sekä funktionaalisen että logiikkaohjelmoinnin ominaisuuksista. Samalla tavalla vaikuttava tekijä on myös laiskuus. Jotkut käyttötarkoitukset hyötyvät näistä ominaisuuksista, toisissa ne ovat haittoja. Käymme seuraavaksi läpi Curryn tärkeimpien suunnitteluvalintojen ja paradigmojen pääpiirteisiä etuja ja haittoja sekä luettelemme joitakin Currylle lupaavia ja epäsopivilta vaikuttavia käyttökohteita.</p>

<a name="etujajahaittoja8" />
<h2>Arvioita eduista ja haitoista</h2>

<h3>Funktionaalisuus</h3>
<p>Sivuvaikutusten näkyminen tyyppitasolla mahdollistaa taatusti sivuvaikutuksettomat aliohjelmat. Lisäksi ensimmäisen luokan funktiot ja niiden helppo syntaksi mahdollistavat elegantin funktionaalisen tyylin ja korkean abstraktiotason. Suuresti tilasta (<em>state</em>) riippuvaiset ohjelmat voivat kuitenkin olla vaikeita toteuttaa.</p>

<h3>Logiikkaohjelmointi</h3>
<p>Loogisen epädeterminismin ja funktionaalisten korkeamman asteen funktioiden yhdistelmä mahdollistaa abstraktin korkeamman asteen logiikkahjelmointityylin, joka ei ole mahdollinen perinteisessä logiikkaohjelmointikielissä. Looginen ratkaisun etsintä on kuitenkin usein merkittävästi hitaampaa kuin funktionaalinen funktion evaluointi. Curryn yhdistetystä tyylistä seuraa, että ohjelmoijan on oltava tarkka varmistaakseen että ei vahingossa tule etsineeksi ratkaisua, kun tarkoitus on vain evaluoida funktio.</p>

<h3>Laiskuus</h3>
<p>Laiskuus mahdollistaa äärettömien tietorakenteiden käsittelyn. Evaluoimista rajoittavia optimisaatioita ei tarvita, koska vain se evaluoidaan, mikä on pakko evaluoida. Evaluointikäyttäytyminen ja siten ohjelman viemä aika ja tila voivat kuitenkin olla vaikeita ennustaa.</p>

<a name="kayttokohteita" />
<h2>Käyttökohteita</h2>

<p>Esitetään lopuksi joitakin lupaavilta vaikuttavia käyttökohteita Currylle:
<ul>
<li>Esimerkkien tai vastaesimerkkien etsiminen matemaattiselle konjektuurille.</li>
<li>Yleisemmin matemaattisten väitteiden tietokoneavusteinen todistus (<em>theorem proving</em>).</li>
<li>Viihteellisten logiikkapähkinöiden laskennallinen ratkaisu.</li>
<li>Luonnollisen kielen käsittely (klassinen Prologin sovelluskohde)</li>

</ul></p>

Curry ei tunnu soveltuvan hyvin mikään käyttötarkoitukseen, joka edellyttäisi laajaa standardikirjastoa. Se ei myöskään solvellu hyvin skriptien kirjoittamiseen eikä oliopohjaiseen ohjelmointiin.

<hr />

<a name="lahteet" />
<h1>Lähteet</h1>
<table border="0">

<tr>
<td valign="top">[Cur11]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Curry (programming language) <a href="http://en.wikipedia.org/wiki/Curry_(programming_language)">http://en.wikipedia.org/wiki/Curry_(programming_language)</a> (viitattu 27.4.2011)</td>

</tr>

<tr>
<td valign="top">[AHL05]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Antony, S., Hanus, M., Liu, J. & Tolmach, A. A Virtual Machine for Functional Logic Computations. Teoksessa Grelck et al. (toim.) <i>Implementation and Application of Functional Languages</i>, Lecture Notes in Computer Science, vol. 3474/2005, s. 427-488, 2005. <a href="http://web.cecs.pdx.edu/~antoy/homepage/publications/ifl04/paper.pdf">http://web.cecs.pdx.edu/~antoy/homepage/publications/ifl04/paper.pdf</a> (viitattu 20.3.2011)</td>
</tr>

<tr>

<td valign="top">[AnH07]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Antony, S. & Hanus, M. Curry: A Tutorial Intorduction. 2007. <a href="http://www-ps.informatik.uni-kiel.de/currywiki/_media/documentation/tutorial.pdf">http://www-ps.informatik.uni-kiel.de/currywiki/_media/documentation/tutorial.pdf</a> (viitattu 20.3.2011)</td>
</tr>

<tr>
<td valign="top">[AnH10]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Antony, S. & Hanus, M. Functional Logic Programming. <i>Communications of the ACM</i>, 53(4), 2010. <a href="http://doi.acm.org/10.1145/1721654.1721675">http://doi.acm.org/10.1145/1721654.1721675</a> (viitattu 20.3.2011)</td>

</tr>

<tr>
<td valign="top">[DaM82]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Damas, L. & Milner, R. Principal type-schemes for functional programs. Teoksessa <i>Proc. 9th Annual Symposium on Principles of Programming Languages</i>, s.207-212, 1982. <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.122.3604&rep=rep1&type=pdf">http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.122.3604&rep=rep1&type=pdf</a> (viitattu 20.3.2011)</td>
</tr>

<tr>
<td valign="top">[Han99]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. Distributed programming in a multi-paradigm declarative language. Teoksessa <i>Proc. of the International Conference on Principles and Practice of Declarative Programming</i>, s. 188-205, 1999. <a href="http://www.informatik.uni-kiel.de/~mh/papers/PPDP99.html">http://www.informatik.uni-kiel.de/~mh/papers/PPDP99.html</a> (viitattu 27.4.2011)
</tr>

<tr>
<td valign="top">[Han00]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. A functional logic programming approach to graphical user interfaces. Teoksessa <i>Proc. of the Second International Workshop on Practical Aspects of Declarative Languages</i>, s. 47-62, 2000. <a href="http://www.informatik.uni-kiel.de/~mh/papers/PADL00.html">http://www.informatik.uni-kiel.de/~mh/papers/PADL00.html</a> (viitattu 27.4.2011)

</tr>

<tr>
<td valign="top">[Han01]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. High-level server side web scripting in Curry. Teoksessa <i>Proc. of the Third International Symposium on Practical Aspects of Declarative Languages</i>, s. 76-92, 2001. <a href="http://www.informatik.uni-kiel.de/~mh/papers/PADL01.html">http://www.informatik.uni-kiel.de/~mh/papers/PADL01.html</a> (viitattu 27.4.2011)
</tr>

<tr>
<td valign="top">[Han04]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. Dynamic predicates in functional logic programs. <i>Journal of Functional and Logic Programming</i>, 2004(5), 2004. <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.69.6838&rep=rep1&type=pdf">http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.69.6838&rep=rep1&type=pdf</a> (viitattu 27.4.2011)</td>

</tr>

<tr>
<td valign="top">[Han06]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. (toim.) Curry: An Integrated Functional Logic Language. 2006. <a href="http://www-ps.informatik.uni-kiel.de/currywiki/_media/documentation/report.pdf">http://www-ps.informatik.uni-kiel.de/currywiki/_media/documentation/report.pdf</a> (viitattu 20.3.2011)</td>
</tr>

<tr>
<td valign="top">[Han11a]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. (toim.) Curry: A Truly Integrated Functional Language. <a href="http://www.curry-language.org">http://www.curry-language.org</a> (viitattu 19.3.2011)</td>

</tr>

<tr>
<td valign="top">[Han11b]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Hanus, M. (toim.) PACKS 1.9.2 The Portland Aachen Kiel Curry System: User Manual. 2011. <a href="http://www.informatik.uni-kiel.de/~pakcs/Manual.pdf">http://www.informatik.uni-kiel.de/~pakcs/Manual.pdf</a></td>
</tr>

<tr>
<td valign="top">[Lux11]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Lux, W. Münster Curry: User's Guide. 2011. <a href="http://danae.uni-muenster.de/~lux/curry/user.html">http://danae.uni-muenster.de/~lux/curry/user.html</a></td>

</tr>

<tr>
<td valign="top">[Sco00]</td> <td>&nbsp&nbsp&nbsp&nbsp</td> <td>Scott, M. L. Programming language pragmatics. Morgan Kaufmann Publishers. 2000.</td>
</tr>
</table>
</sisalto>
</body>
</html>